//
// Created by jiao on 2021/4/19.
//

#include <sys/eventfd.h>
#include <pthread.h>
#include "YHMainHandler.h"
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/eventfd.h>
#include "jni.h"
#include <cerrno>

//退出循环的标志
static const int EXIT_IDENT = -2;

int YHMainHandler::mainLooperCallBack(int fd, int events, void *data) {
    auto *handler = static_cast<YHMainHandler *>(data);
    handler->runMain();
    return 1;
}

YHMainHandler::YHMainHandler(YqHandlerCallBackFunc *callBack) : mCallBack(callBack) {

    mEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if (mEventFd < 0) {
        YH_HANDLER_LOGE("YHMainHandler Could not create epoll instance: %s", strerror(errno));
    }
    pthread_mutex_init(&mLooper_mutex_, NULL);
    mainLopper = ALooper_forThread();
    ALooper_addFd(mainLopper, mEventFd, mEventFd, ALOOPER_EVENT_INPUT, mainLooperCallBack, this);
}

YHMainHandler::~YHMainHandler() {
    YQ_HANDLER_LOGD("YHMainHandler  折构方法");
}

void YHMainHandler::runMain() {
    //当前需要处理的任务
    std::vector<std::pair<int, void *>> curQueue;
    //是否退出循环
    bool isExit = false;

    pthread_mutex_lock(&mLooper_mutex_);
    awoken();
    if (!mQueue.empty()) {
        for (auto data:mQueue) {
            if (data.first == EXIT_IDENT) {
                isExit = true;
                break;
            }
            curQueue.push_back(data);
        }
    }
    mQueue.clear();
    pthread_mutex_unlock(&mLooper_mutex_);
    for (auto data:curQueue) {
        mCallBack(data.first, data.second);
    }
    curQueue.clear();
    if (isExit) {
        destroy();
    }


}


void YHMainHandler::sendMessage(int ident, void *data) {
    if (isQuit)return;
    pthread_mutex_lock(&mLooper_mutex_);
    mQueue.emplace_back(ident, data);
//    if (mQueue.size() == 1) {//如果数据大于1，则不需要唤醒 以为已经唤醒过
    wake();
//    }
    pthread_mutex_unlock(&mLooper_mutex_);


}

void YHMainHandler::removeMessage(int ident) {
    pthread_mutex_lock(&mLooper_mutex_);
    std::vector<std::pair<int, void *>>::iterator iter;
    for (iter = mQueue.begin(); iter != mQueue.end();) {
        auto tmp = *iter;
        if (tmp.first == ident) {
            iter = mQueue.erase(iter);
        } else {
            ++iter;
        }
    }
    pthread_mutex_unlock(&mLooper_mutex_);
}

void YHMainHandler::removeAll() {
    if (isQuit)return;
    pthread_mutex_lock(&mLooper_mutex_);
    mQueue.clear();
    pthread_mutex_unlock(&mLooper_mutex_);

}

void YHMainHandler::destroy() {
    YQ_HANDLER_LOGD("YHMainHandler destroy");

    isQuit = true;
    pthread_mutex_destroy(&mLooper_mutex_);
    mQueue.clear();
    close(mEventFd);
    mEventFd = -1;
    ALooper_removeFd(mainLopper, mEventFd);
    mainLopper = nullptr;
    mCallBack = nullptr;
    delete this;
}

void YHMainHandler::wake() {
    YQ_HANDLER_LOGD("YHMainHandler %p ~ wake", this);
    uint64_t inc = 1;
    ssize_t nWrite = TEMP_FAILURE_RETRY(write(mEventFd, &inc, sizeof(uint64_t)));
    if (nWrite != sizeof(uint64_t)) {
        if (errno != EAGAIN) {
            YH_HANDLER_LOGE("YHMainHandler  Could not write wake signal to fd %d: %s",
                            mEventFd, strerror(errno));
        }
    }
}

void YHMainHandler::awoken() {
    YQ_HANDLER_LOGD("YHMainHandler %p ~ awoken", this);
    uint64_t counter;
    TEMP_FAILURE_RETRY(read(mEventFd, &counter, sizeof(uint64_t)));
}

void YHMainHandler::quit() {
    sendMessage(EXIT_IDENT, NULL);
}

